package edu.stu.cs.software.family.base.web.spring.controller;

import java.io.IOException;
import java.io.Serializable;
import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import edu.stu.cs.software.family.base.domain.BaseEntity;
import edu.stu.cs.software.family.base.service.GenericManager;

public class GenericController<T extends BaseEntity<LG>, LG extends Serializable, M extends GenericManager<T, LG>>
		extends BaseController {

	protected LG id;
	protected M manager;
	protected T model;
	protected Page<T> page;

	protected Pageable pageable;
	protected int pageNumber = 0;
	protected int pageSize = 20;

	/**
	 * @param model entity model
	 * @return new created entity
	 */
	@RequestMapping(value = "/add", method = RequestMethod.POST, produces = "application/json;charset=UTF-8", consumes = "application/json")
	@ResponseBody
	public T create(@RequestBody T model) {
		this.model = model;
		this.model = this.manager.save(this.model);
		return this.model;
	}

	/**
	 * @param id entity id
	 * @throws IOException
	 */
	@RequestMapping(value = "/delete/{id}", method = RequestMethod.DELETE, produces = "application/json")
	@ResponseBody
	public void delete(@PathVariable LG id) throws IOException {
		this.manager.delete(id);
	}
	@RequestMapping(value = "/deleteMore", method = RequestMethod.DELETE, produces = "application/json")
	@ResponseBody
	public void deleteMore(@RequestParam LG[] ids) throws IOException {
		this.manager.deleteMore(ids);
	}
	/**
	 * @param id entity id
	 * @return found entity
	 */
	@RequestMapping(value = "/findById/{id}", method = RequestMethod.GET, produces = "application/json")
	@ResponseBody
	public T findById(@PathVariable LG id) {
		return this.manager.findById(id);

	}
	/**
	 * find by entity of userName
	 * @param name
	 * @param pageNumber
	 * @param pageSize
	 * @return
	 */
//	@RequestMapping(value = "/findPageByName",method = RequestMethod.GET, produces = "application/json")
//    @ResponseBody
//    public Page<T> findPageByName(@RequestParam String name,@RequestParam Integer pageNumber,@RequestParam Integer pageSize) {
//        this.pageNumber = pageNumber-1;
//        this.pageSize = pageSize;
//        this.pageable = PageRequest.of(this.pageNumber, this.pageSize, Sort.by(Sort.Direction.ASC, "id"));
//        this.page = this.manager.findByName(name,this.pageable);
//        return this.page;
//    }
	/**
	 * 
	 * @return
	 */
	@RequestMapping(value = "/findAll", method = RequestMethod.GET, produces = "application/json")	
	public List<T> findAll(){
		return this.manager.findAll();
		
	}
	/**
	 * 
	 * 
	 * @param pageNumber number order of current page
	 * @param pageSize   size of current page
	 * @return page able entity list
	 */
	@RequestMapping(value = "/findPage", method = RequestMethod.GET, produces = "application/json")
	@ResponseBody
	public Page<T> findPage(@RequestParam Integer pageNumber,@RequestParam Integer pageSize) {
		this.pageNumber = pageNumber-1;
        this.pageSize = pageSize;
		this.pageable = PageRequest.of(this.pageNumber, this.pageSize, Sort.by(Direction.ASC, "id"));
		this.page = this.manager.findAll(this.pageable);
		logger.info(this.page);
		return this.page;
	}

	/**
	 * @param id entity code to update
	 * @param model entity information to update
	 * @return updated entity
	 */
	@RequestMapping(value = "/update/{id}", method = RequestMethod.PUT,produces = "application/json;charset=UTF-8", consumes = "application/json")
	@ResponseBody
	public T update(@PathVariable LG id, @RequestBody T model) {
		model.setId(id);
		this.model = this.manager.save(model);
		return this.model;
	}

}
